/*
  Losu Copyright Notice
  --------------------
    Losu is an open source programming language project under the MIT license
  that can be used for both academic and commercial purposes. There are no
  fees, no royalties, and no GNU-like "copyright" restrictions. Losu qualifies
  as open source software. However, Losu is not public property, and founder
  'chen-chaochen' retains its copyright.

    Losu has been registered with the National Copyright Administration of the
  People's Republic of China, and adopts the MIT license as the copyright
  licensing contract under which the right holder conditionally licenses its
  reproduction, distribution, and modification rights to an unspecified public.

    If you use Losu, please follow the public MIT agreement or choose to enter
  into a dedicated license agreement with us.

  The MIT LICENSE is as follows
  --------------------
  Copyright  2020 - now  chen-chaochen

    Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the “Software”), to
  deal in the Software without restriction, including without limitation the
  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  sell copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

/*
 * To introduce Losu into your project, you simply reference this header file
 * in the project source code and link the Losu kernel to the target binary
 */

#ifndef define_included_losu_h
#define define_included_losu_h
#include <limits.h>
#include <setjmp.h>
#include <stddef.h>
#include <stdint.h>

/*! Include LosuConfig

  Include losuconfig.h to configure Losu-Language.
  If you don't have losuconfig.h, it will use the default configuration
*/
#ifndef define_included_losuconfig_h
/* try to include losuconfig.h */
#ifdef __has_include
#if __has_include("losu_config.h")
#include "losu_config.h"
#endif /* __has_include("losuconfig.h") */
#else
#include "losu_config.h"
#endif /* __has_include */

/* if losuconfig.h is not found, error*/

#ifndef define_included_losuconfig_h
#error "Configuration file not found 'losu_config.h'"
#endif /* define_included_losuconfig_h */
#endif /* define_included_losuconfig_h */

/* check config is right? */

/*! Limit Vsize_t of Losu-Language

  Losu-Language uses Vsize_t to store the size of variables.
  Losu 2.x dropped support for 16-bit processors (still works fine on some
  devices),and limiting the instruction set length of the Losu-VM to 32-bit
  (new standard, NOT v1.x ). This will improve the performance and
  generalizability of Losu code to some extent!

  Q: Does using 32-bit instructions have any negative effect on the
  modernization properties of Losu? Does it appear:
    1. only 32-bit executables can be fetched
    2. not be able to access memory space beyond 4G
    3. not being able to use supported libraries on 64-bit systems
    4. ......
  A: No, Losu 2.x does not have any of these problems.
  The impact of 32-bit instructions is limited to internal LosuVM,which we can
  implement:
    1. provide 64-bit executables
    2. provide more than 4G of memory space for the application
    3. work in coordination with the 64-bit support libraries on the system

  However,As an advanced feature, 64-bit Universal Instruction Set (UIS)
  support has been added to Losu 2.x,and is enabled by default on 64-bit
  systems, providing better performance, more features and more room for
  expansion.

*/
#ifndef define_file_losu_h__inline__vsize_t
#define define_file_losu_h__inline__vsize_t

/* define LosuVmInlineType (ISO-Ctype to Losu-VmCtype) */

typedef double _l_number;
typedef uint8_t _l_bool;
typedef uint64_t _l_size_t;
typedef uint32_t _l_hash;
typedef int64_t _l_gcint;

/* define Losu BitSize as */
#ifndef vmIns_SizeIns
#ifndef __config_losucore_vm_bitsize
#define __config_losucore_vm_bitsize (__SIZEOF_SIZE_T__ * 8)
#endif /* __config_losucore_vm_bitsize */

#define vmIns_SizeIns __config_losucore_vm_bitsize

#if vmIns_SizeIns == 32
#define define_file_losu_h_vmbitsize
typedef uint32_t vmInstruction;
#endif /* vmIns_SizeIns == 32 */

#if vmIns_SizeIns == 64
#define define_file_losu_h_vmbitsize
typedef uint64_t vmInstruction;
#endif /* vmIns_SizeIns == 64 */

#ifndef define_file_losu_h_vmbitsize
#error "vmIns_SizeIns must be 32 or 64"
#endif /* define_file_losu_h_vmbitsize */

#endif /* vmIns_SizeIns */

#endif /* define_file_losu_h__inline__vsize_t */

/*! Losu Error-Code Subsystem

  Losu 2.x uses a new error-code subsystem,which is more flexible and
  powerful,than the old error-code system.

  In the new version, Losu returns different values for different types of
  errors and puts the VM in an "error" state, which can be caught and handled
  by higher-level programs.
*/
#ifndef define_file_losu_h__inline__LosuErrorCode
#define define_file_losu_h__inline__LosuErrorCode

#define LosuErrorCode_Ok 0      /* Success */
#define LosuErrorCode_Runtime 1 /* Runtime Error */
#define LosuErrorCode_File 2    /* File Error */
#define LosuErrorCode_Syntax 3  /* Syntax error */
#define LosuErrorCode_Mem 4     /* Memory error */
#define LosuErrorCode_Heap 5    /* Stack Overflow */
#define LosuErrorCode_Library 6 /* Module loading */
#define LosuErrorCode_Over -1   /* Catastrophic crash */

#endif /* define_file_losu_h__inline__LosuErrorCode */

/*! Define Losu Vtype
  Losu Vtype is a type that can be used by LosuVm to store different types of
  data. It can be abstracted into a unified LosuObj and its aliases, including
  strings, numbers, functions, maps, and many other built-in types.
*/
#ifndef define_file_losu_h__inline__LosuVtype
#define define_file_losu_h__inline__LosuVtype

/* LosuVm */
typedef struct LosuVm LosuVm;
/* losuObj */
typedef struct LosuObj LosuObj;
/*  _inlineString */
typedef struct _inlineString _inlineString;
/*  _inlineFunction */
typedef struct _inlineFunction _inlineFunction;
/*  _inlineHash */
typedef struct _inlineHash _inlineHash;
/* _inlineCallinfo */
typedef struct _inlineCallinfo _inlineCallinfo;
/* _inlineLocalvar */
typedef struct _inlineLocalvar _inlineLocalvar;
/* LosuNode */
typedef struct LosuNode LosuNode;
/* LosuApi */
typedef int32_t (*LosuApi) (LosuVm *vm);
/* _inlineScode */
typedef struct _inlineScode _inlineScode;
/* LosuModule */
typedef struct LosuModule LosuModule;
/*  */
typedef struct LosuPackage_t LosuPackage_t;

#define LosuTypeDefine_null 0
#define LosuTypeDefine_number 1
#define LosuTypeDefine_string 2
#define LosuTypeDefine_function 3
#define LosuTypeDefine_unit 4
#define LosuTypeDefine_ptr 5
#define LosuTypeDefine_mark 6
#define LosuTypeDefine_byte 7

#endif /* define_file_losu_h__inline__LosuVtype */

/*! Declare Export Info, such as copyright,version,API ...
  We use `LosuExtern` to export external declarations that follow the C ABI
  rules, whether they are integrated into a C or C++ project.
*/
#ifndef define_file_losu_h__inline__LosuExternInfo
#define define_file_losu_h__inline__LosuExternInfo

/* check if g++ */
#ifndef LosuExtern
#ifdef __cplusplus
#define LosuExtern extern "C"
#else
#define LosuExtern extern
#endif
#endif /* LosuExtern */

/* Export Value */
LosuExtern _l_size_t LosuVersionNum;
LosuExtern const char LosuVersion[];     /* Version */
LosuExtern const char LosuCopyright[];   /* (C)copy */
LosuExtern const char LosuBuild[];       /* Build info, date,time,patch ... */
LosuExtern const char LosuArch[];        /* Arch Info,Os and CPU*/
LosuExtern const char *LosuTypeSystem[]; /* Type System Info */
LosuExtern LosuPackage_t *LosuPackages;  /* Losu Packages */

#ifndef define_file_losu_h__inline__losuapi
#define define_file_losu_h__inline__losuapi
/* Export Losu API */

/* API: vm_xxx  create, control, and manage VM APIs */

LosuExtern LosuVm *vm_create (int stacksize);
LosuExtern int vm_init (LosuVm *vm, int32_t argc, const char **argv);
LosuExtern LosuVm *vm_fork (LosuVm *vm, int size);
LosuExtern void vm_stop (LosuVm *vm);
LosuExtern void vm_error (LosuVm *vm, int ecode, const char *estr, ...);
LosuExtern void vm_warning (LosuVm *vm, const char *estr, ...);
LosuExtern int32_t vm_dofile (LosuVm *vm, const char *filename);
LosuExtern int32_t vm_dostring (LosuVm *vm, const char *str, const char *name);
LosuExtern int32_t vm_dobyte (LosuVm *vm, const char *byte, size_t len,
                              const char *name);
LosuExtern int32_t vm_loadfile (LosuVm *vm, const char *f);
LosuExtern int32_t vm_loadstring (LosuVm *vm, const char *s, const char *name);
LosuExtern int32_t vm_loadbyte (LosuVm *vm, const char *byte, size_t len,
                                const char *name);
LosuExtern int32_t vm_execute (LosuVm *vm, int32_t narg, int32_t nres,
                               const char *name);
LosuExtern LosuObj *vm_getval (LosuVm *vm, const char *name);
LosuExtern void vm_setval (LosuVm *vm, const char *name, LosuObj val);
LosuExtern void vm_close (LosuVm *vm);

/* API: gc_xxx: Manage GC workflow APIs */

LosuExtern void gc_setmax (LosuVm *vm, _l_gcint size);
LosuExtern _l_gcint gc_getmemNow (LosuVm *vm);
LosuExtern _l_gcint gc_getmemMax (LosuVm *vm);
LosuExtern _l_bool gc_collect (LosuVm *vm);

/* API: arg_xxx: Operation arguments on the call-stack APIs */

LosuExtern LosuObj *arg_get (LosuVm *vm, int idx);
LosuExtern void arg_return (LosuVm *vm, LosuObj obj);
LosuExtern int32_t arg_num (LosuVm *vm);
LosuExtern _l_number arg_getnum (LosuVm *vm, int idx);
LosuExtern const char *arg_getstr (LosuVm *vm, int idx);
LosuExtern char *arg_getptr (LosuVm *vm, int idx);
LosuExtern LosuApi arg_getfunc (LosuVm *vm, int idx);
LosuExtern int arg_gettype (LosuVm *vm, int idx);
LosuExtern const char *arg_gettypeStr (LosuVm *vm, int idx);
LosuExtern void arg_returnnum (LosuVm *vm, _l_number num);
LosuExtern void arg_returnstr (LosuVm *vm, const char *str);
LosuExtern void arg_returnstrlen (LosuVm *vm, const char *str, size_t len);
LosuExtern void arg_returnfunc (LosuVm *vm, LosuApi func);
LosuExtern void arg_returnptr (LosuVm *vm, char *ptr);
LosuExtern void arg_returnnull (LosuVm *vm);

/* API: obj_xxx: Create and edit LosuObj APIs */

LosuExtern const char *obj_tostr (LosuVm *vm, LosuObj *obj);
LosuExtern _l_number obj_tonum (LosuVm *vm, LosuObj *obj);
LosuExtern char *obj_toptr (LosuVm *vm, LosuObj *obj);
LosuExtern LosuApi obj_tofunction (LosuVm *vm, LosuObj *obj);
LosuExtern int obj_type (LosuVm *vm, LosuObj *obj);
LosuExtern const char *obj_typeStr (LosuVm *vm, LosuObj *obj);
LosuExtern LosuObj obj_newstr (LosuVm *vm, char *str);
LosuExtern LosuObj obj_newstrlen (LosuVm *vm, char *str, size_t len);
LosuExtern size_t obj_getstrlen (LosuVm *vm, LosuObj *obj);
LosuExtern LosuObj obj_newnum (LosuVm *vm, _l_number num);
LosuExtern LosuObj obj_newfunction (LosuVm *vm, LosuApi func);
LosuExtern LosuObj obj_newnull (LosuVm *vm);
LosuExtern LosuObj obj_newunit (LosuVm *vm);
LosuExtern LosuObj obj_newptr (LosuVm *vm, char *ptr);
LosuExtern LosuObj *obj_indexunit (LosuVm *vm, LosuObj unit, LosuObj key);
LosuExtern LosuObj *obj_indexunitbynum (LosuVm *vm, LosuObj unit, _l_number i);
LosuExtern LosuObj *obj_indexunitbystr (LosuVm *vm, LosuObj unit, char *s);
LosuExtern void obj_setunit (LosuVm *vm, LosuObj unit, LosuObj key,
                             LosuObj value);
LosuExtern void obj_setunitbynum (LosuVm *vm, LosuObj unit, _l_number key,
                                  LosuObj value);
LosuExtern void obj_setunitbystr (LosuVm *vm, LosuObj unit, char *key,
                                  LosuObj value);
LosuExtern LosuNode *obj_unit_first (LosuVm *vm, LosuObj unit);
LosuExtern LosuNode obj_unit_location (LosuVm *vm, LosuObj unit, LosuObj key);
LosuExtern LosuNode *obj_unit_next (LosuVm *vm, LosuObj unit, LosuNode *n);
LosuExtern LosuObj obj_unit_nodekey (LosuVm *vm, LosuNode *n);
LosuExtern LosuObj obj_unit_nodevalue (LosuVm *vm, LosuNode *n);

/* API: stack_xxx: Stack Opereatetion APIs */

LosuExtern void stack_push (LosuVm *vm, LosuObj o);
LosuExtern void stack_pop (LosuVm *vm, int i);
LosuExtern void stack_call (LosuVm *vm, int argnum, int resnum);

/* API: charset_xxx: Charset APIs， */
LosuExtern char *charset_toSys (const char *s);
LosuExtern char *charset_toLosu (const char *s);
LosuExtern char *charset_newObj_toLosu (LosuVm *vm, const char *s);
LosuExtern char *charset_newObj_toSys (LosuVm *vm, const char *s);

#endif /* define_file_losu_h__inline__losuapi */

#endif /* define_file_losu_h__inline__LosuExternInfo */

/*! Define the Struct of LosuVtype
  We define LosuVtype using typedef and structs, which store information about
  individual objects at runtime in the virtual machine
*/
#ifndef define_file_losu_h__inline__LosuVtypeDefine
#define define_file_losu_h__inline__LosuVtypeDefine

typedef struct LosuObj
{
  uint8_t type; /* type of the object */
  union
  {
    struct _inlineString *str;    /* string type*/
    struct _inlineFunction *func; /* function type*/
    struct _inlineHash *hash;     /* hash type*/
    struct _inlineCallinfo *call; /* callinfo type*/
    _l_number num;                /* number type*/
    void *ptr;                    /* pointer type*/
  } value;
} LosuObj;

typedef struct _inlineString
{
  _l_hash hash;               /* Hash Value*/
  int32_t cstidx;             /* Const Index*/
  size_t len;                 /* Length of the string*/
  struct _inlineString *next; /* Next StringObj (in equal-key link list) */
  int16_t marked;             /* Marked for GC*/
  char str[4];                /* Memory space for string value*/
} _inlineString;

typedef struct _inlineFunction
{
  union
  {
    LosuApi capi;               /* C-API */
    struct _inlineScode *sdef;  /* Losu Script `def` */
  } func;                       /* function segment */
  struct _inlineFunction *next; /* Next FunctionObj (in equal-key link list) */
  struct _inlineFunction
      *mark;        /* Mark link when GC working, default o.mark == o */
  _l_bool isC;      /* Is C-API, 1 if is, 0 if not */
  int32_t nclosure; /* Number of closure upvalue */
  struct LosuObj closure[1]; /* Closure upvalue segment */
} _inlineFunction;

typedef struct LosuNode
{
  struct LosuObj key;
  struct LosuObj value;
  struct LosuNode *next;
} LosuNode;

typedef struct _inlineHash
{
  int32_t size;
  struct LosuNode *node;
  struct LosuNode *free;    /* Free node point */
  struct _inlineHash *next; /* Next HashObj (in equal-key link list) */
  struct _inlineHash
      *mark; /* Mark link when GC working, default o.mark == o */
} _inlineHash;

typedef struct _inlineCallinfo
{
  struct _inlineFunction *func; /* Calle */
  const vmInstruction **pc;     /* Current PC of Calle */
} _inlineCallinfo;

typedef struct _inlineLocalvar
{
  struct _inlineString *name; /* Name of the local variable */
  int startpc;
  int endpc;
} _inlineLocalvar;

typedef struct _inlineScode
{
  /* Local segment */
  /* Number */
  _l_number *lcnum; /* Number used by this function */
  int32_t nlcnum;   /* Number of lcnum */

  /* String */
  struct _inlineString **lcstr; /* String used by this function */
  int32_t nlcstr;               /* Number of  lcstr  */

  /* Function */
  struct _inlineScode **lcscode; /* Inline-function of this function */
  int32_t nlcscode;              /* Number of lcscode */

  /* Local Var */
  struct _inlineLocalvar *localvar; /* Localvar used by this function */
  int32_t nlocalvar;                /* Number of localvars */

  /* Instruction Segment */
  vmInstruction *code; /* Instruction of this function */
  int32_t ncode;       /* Number of code (MAX == INT_MAX,C-type) */

  /* Arg Segment */
  int8_t narg;    /* Number of arguments */
  _l_bool isVarg; /* is ... */
  int16_t maxstacksize;

  /* Lineinfo Segment */
  int32_t *lineinfo;
  int32_t nlineinfo;
  int32_t defedline;

  /* Data Segment */
  struct _inlineScode *next; /* Next ScodeObj (in equal-key link list) */
  struct _inlineString *src; /* Source code */

  /* Gc Segment */
  _l_bool marked;

} _inlineScode;

typedef struct LosuModule
{
  const char *name;
  LosuApi construct;
} LosuModule;

#ifndef __config_losucore_vm_vmbuff
#define __config_losucore_vm_vmbuff 128
#endif

typedef struct __longjump __longjump;
typedef struct __vmStrseg
{
  _l_hash size;
  _l_hash nsize;
  _inlineString **strobj;
} __vmStrseg;

typedef struct LosuVm
{
  LosuVm *mainthread; /* Root-Vm */
  LosuObj *top, *stack, *stackmax, *base;
  int32_t stacksize;

  __longjump *errjmp;
  __longjump *emjmp; /* 紧急跳转，跳转到虚拟机的创建者处 */

  unsigned char *bufftmp;
  _l_size_t nbufftmp;

  _inlineScode *inspool;     /* InstructionObj  */
  _inlineFunction *funcpool; /* FunctionObj */
  _inlineHash *hashpool;     /* HashObj (unit) */
  __vmStrseg strpool;        /* StringObj (string) */

  _inlineHash *global; /* global var-table */

  _l_gcint gcDymax; /* Dynatic Max Limit */
  _l_gcint nblocks; /* Now size */
  _l_gcint gcMax;   /* All Max */
  _l_gcint gcHook;  /* hookMax */

  unsigned char staticbuff[__config_losucore_vm_vmbuff];
  const char *name;

} LosuVm;

typedef struct __longjump
{
  __longjump *pre;
  jmp_buf jmpflag;
  volatile int16_t err;
} __longjump;

typedef struct LosuPackage_t
{
  const char *name;
  LosuModule *(*loadfunc) ();
} LosuPackage_t;
#endif

#endif /* define_included_losu_h */
